import AliOssUploadRequestDTO from "../../../model/dto/fileserver/AliOssUploadRequestDTO";
import Logger from "../../../log/Logger";
import Beans from "../../../common/utils";
import R from "../../../model/protocol/R";
import ApiResponse from "../../apis/ApiResponse";
import { FileInfo, FileServerConfig, FileUploadConfig, FileUploadListener, IFileServerClient, UploadError } from "../FileServerClient";
import Fetch from "./Fetch";
import { SuffixToFileType, SuffixToMime } from "./SuffixMime";

// 阿里云OSS服务器APIS
const OSS_API_URL = {
    UPLOAD_SIGN:'common/oss/get_upload_sign',
    SYNC_CALLBACK:'common/oss/upload_sync_callback',
};

// 本地服务器APIS
const FILE_API_URL = {
    UPLOAD_SIGN:'common/file/get_upload_sign',
};

export  default class AbstractClient implements IFileServerClient{
    protected serverConfig: FileServerConfig;
    protected uploadConfig: FileUploadConfig|any;
    protected beforeUploadCallback: ((info:FileInfo)=>FileInfo)|undefined;
    protected progressCallback: ((info:FileInfo)=>void)|undefined;
    protected uploadedCallback: ((info:FileInfo)=>void)|undefined;
    protected errorCallback: ((info:FileInfo|undefined, error:UploadError)=>void)|undefined;
    protected fileInfo:FileInfo|any;
    protected signInfo:AliOssUploadRequestDTO|any;
    protected uploader:any;
    protected sdkKey: string;
    constructor(serverConfig: FileServerConfig, sdkKey:string){
        this.serverConfig = serverConfig;
        this.sdkKey = sdkKey;
    }
    upload(path:string):string{
        return ''
    }

    public init(uploadConfig: FileUploadConfig, listeners: FileUploadListener|undefined): void {
    }

    // 获取提交FORM 的请求参数
    protected buildFormParams(fileInfo:FileInfo|any, cb:(host, any)=>void):any{
        let new_multipart_params:any = {};
        const self = this;
        this.fetchUploadSign(fileInfo).then((resp)=>{
            self.signInfo = resp.data;
            let formParams:any = {};
            if(this.serverConfig.use === 'aliyun'){
                formParams = {
                    'key' : resp.data.dir,
                    'policy': resp.data.policy,
                    'OSSAccessKeyId': resp.data.accessid,
                    'success_action_status' : '200', //让服务端返回200,不然，默认会返回204
                    'callback' : resp.data.callback,
                    'signature': resp.data.signature,
                };
                // 若callback 未设置，删除该属性
                if(!formParams.callback){
                    delete formParams.callback;
                }
            }
            else if(this.serverConfig.use === 'local'){
                formParams = {
                    'signature': resp.data.signature,
                };
            }
            if(typeof cb === 'function'){
                cb(resp.data.host, formParams);
            }
        }).catch((e)=>{
            Logger.trace(e);
            self.setErrorCallback(702, e+"");
        });
    }

    protected setErrorCallback(code:number, msg:string){
        if(typeof this.errorCallback === 'function'){
            const error = new UploadError();
            error.code = code;
            error.msg = msg;
            this.errorCallback(this.fileInfo, error);
        }
    }


    // ---------------------- fetch apis ------------------------//
    // 发送同步回调
    protected sendSyncUploadCallback:(json:any)=>Promise<ApiResponse<any>> = (json:any) => {
        let fetch:any = Fetch.getFetchToolkit();
        let url = '';
        if(this.serverConfig.use === 'aliyun'){
            url = this.serverConfig.baseUrl + '/' + this.serverConfig.version + '/' + OSS_API_URL.SYNC_CALLBACK;
        }
        else if(this.serverConfig.use === 'local'){
            return Promise.resolve();
        }

        const request: any = {method: 'POST', mode: 'cors', headers:{'Content-Type':'application/json'}, body: Beans.json(json)};
        return fetch(url as string, request).then(response =>{
            return response.json();
        }).then(res =>{
            const resp = this.response2ApiResponse(res);
            if(resp.isFailed()){
                return Promise.reject(resp);
            }
            return Promise.resolve(this.response2ApiResponse(res));
        });
    };

    // 获取上传签名
    protected fetchUploadSign(fileInfo:FileInfo|undefined):Promise<ApiResponse<AliOssUploadRequestDTO>> {
        let fetch:any = Fetch.getFetchToolkit();

        if(!fileInfo || !this.uploadConfig){
            return Promise.reject(new ApiResponse(fail()));
        }
        const filename = fileInfo.originFileName;
        let url = '';
        if(this.serverConfig.use === 'aliyun'){
            url = this.serverConfig.baseUrl + '/' + this.serverConfig.version + '/' + OSS_API_URL.UPLOAD_SIGN;
        }
        else if(this.serverConfig.use === 'local'){
            url = this.serverConfig.baseUrl + '/' + this.serverConfig.version + '/' + FILE_API_URL.UPLOAD_SIGN;
        }
        else {
            throw new Error('Not support fileServer type:' + this.serverConfig.use);
        }

        const params = {
            fileType:this.uploadConfig.type || 'FILE',
            fileName:filename.substring(filename.lastIndexOf('/')+1),
            sdkKey:this.sdkKey
        };
        const request: any = {method: 'POST', mode: 'cors', headers:{'Content-Type':'application/json'}, body: Beans.json(params)};
        return fetch(url as string, request).then(response =>{
            return response.json();
        }).then(res =>{
            const resp = this.response2ApiResponse(res);
            if(resp.isFailed()){
                return Promise.reject(resp);
            }
            return Promise.resolve(this.response2ApiResponse(res));
        });
    };


    protected response2ApiResponse( response: R<any>): ApiResponse<any> {
        const apiResponse: ApiResponse<any> = new ApiResponse<any>(true);
        apiResponse.data = response.data;
        apiResponse.errorCode = response.code;
        apiResponse.errorMessage = response.msg;
        apiResponse.raw = response ? Beans.json(response) : '';

        return apiResponse;
    }

    // ---- file type, mime ---- //
    protected getFileType(fileName: string){
        if(this.uploadConfig.type){
            return this.uploadConfig.type.toUpperCase;
        }
        // 从后缀名获取.
        const suffix = fileName.substring(fileName.lastIndexOf('.')+1);
        if(!suffix){
            return 'FILE';
        }
        return SuffixToFileType[suffix] !== undefined ? SuffixToFileType[suffix] : 'FILE';
    }
    protected getMimeType(fileName: string){
        // 从后缀名获取.
        const suffix = fileName.substring(fileName.lastIndexOf('.')+1);
        if(!suffix){
            return 'application/octet-stream';
        }
        return SuffixToMime[suffix] !== undefined ? SuffixToMime[suffix] : 'application/octet-stream';
    }

}
